Now that we know how to model urges using heart rate, we can compute models for each participant and for the global dataset.

Interesting Queries

What were the best overall predictions?

Here, we order the values prioritising accuracy, followed by sensitivity (ability to correctly detect an urge/episode), and lastly specificity (ability to correctly reject non-urges).

From this, I wonder how we can decide the best model…

What were the best predictions for each participant?

We can see that random forest is quite popular (even though its global prediction was low, as compared to this subset):

According to this plot, the random forest consistently performs best (judging by the mean). It is only outperformed in sensitivity, by the neural net (which has poorest mean accuracy and mean specificity) and the Naive Bayesian Tree (which also has poor mean specificity by comparison).

So what did random forest do?

Random forest was able to achieve 100% prediction results on participant 200, and performed poorly with participant 205.

What makes participants 200 and 205 outliers in random forest’s opinion?

First, we compare the model specifications:

By these plots, we can agree that the variables sdnn, sdann, and sdnnix are probably most important as they are found highest both in the global and best model. Let’s confirm by ranking the variable importance in each model:

[1] "Ranks for variable `hr`:"

----------
 Rank   n 
------ ---
  7     4 

  5     3 

  3     2 

  6     2 

  8     2 

  9     2 

  1     1 

  2     1 

  4     1 
----------

[1] "Ranks for variable `meanrr`:"

----------
 Rank   n 
------ ---
  2     4 

  5     4 

  6     3 

  4     2 

  7     2 

  8     2 

  1     1 
----------

[1] "Ranks for variable `sdnn`:"

----------
 Rank   n 
------ ---
  2     8 

  3     4 

  6     2 

  1     1 

  4     1 

  8     1 

  10    1 
----------

[1] "Ranks for variable `sdann`:"

-----------
 Rank   n  
------ ----
  1     12 

  2     2  

  3     2  

  4     2  
-----------

[1] "Ranks for variable `sdnnix`:"

----------
 Rank   n 
------ ---
  5     4 

  1     3 

  3     3 

  4     2 

  9     2 

  2     1 

  6     1 

  7     1 

  8     1 
----------

[1] "Ranks for variable `pnn50`:"

----------
 Rank   n 
------ ---
  4     4 

  6     4 

  3     3 

  5     3 

  2     1 

  7     1 

  9     1 

  10    1 
----------

[1] "Ranks for variable `sdsd`:"

----------
 Rank   n 
------ ---
  9     5 

  8     4 

  5     2 

  6     2 

  7     2 

  3     1 

  4     1 

  10    1 
----------

[1] "Ranks for variable `rmssd`:"

----------
 Rank   n 
------ ---
  8     6 

  9     4 

  3     2 

  4     2 

  7     2 

  6     1 

  10    1 
----------

[1] "Ranks for variable `irrr`:"

----------
 Rank   n 
------ ---
  7     5 

  9     4 

  4     3 

  6     2 

  8     2 

  5     1 

  10    1 
----------

[1] "Ranks for variable `madrr`:"

-----------
 Rank   n  
------ ----
  10    13 

  2     1  

  3     1  

  5     1  

  6     1  

  7     1  
-----------

We can assume that participant 205 had the poorest predictions because their model selected poor variables. What do these variables look like?

Here’s what the global data set looks like:

[1] 2199   11
       hr             meanrr            sdnn            sdann            sdnnix            pnn50       
 Min.   : 45.13   Min.   : 372.4   Min.   : 24.29   Min.   :  0.00   Min.   :  2.293   Min.   :0.0000  
 1st Qu.: 72.54   1st Qu.: 696.0   1st Qu.: 53.57   1st Qu.: 15.22   1st Qu.: 46.073   1st Qu.:0.1088  
 Median : 79.33   Median : 762.8   Median : 64.39   Median : 26.76   Median : 56.843   Median :0.1606  
 Mean   : 81.03   Mean   : 766.6   Mean   : 69.86   Mean   : 34.90   Mean   : 59.880   Mean   :0.1673  
 3rd Qu.: 87.04   3rd Qu.: 833.5   3rd Qu.: 80.17   3rd Qu.: 45.98   3rd Qu.: 69.031   3rd Qu.:0.2258  
 Max.   :162.51   Max.   :1332.5   Max.   :452.62   Max.   :263.32   Max.   :586.990   Max.   :0.6000  
      sdsd            rmssd             irrr            madrr          Episodes
 Min.   : 18.71   Min.   : 18.70   Min.   : 11.72   Min.   :-39.0647   0:1037  
 1st Qu.: 53.95   1st Qu.: 53.86   1st Qu.: 62.50   1st Qu.:  0.0000   1:1162  
 Median : 66.51   Median : 66.21   Median : 62.50   Median :  0.0000           
 Mean   : 71.63   Mean   : 71.23   Mean   : 77.04   Mean   :  1.0660           
 3rd Qu.: 82.94   3rd Qu.: 82.54   3rd Qu.: 93.75   3rd Qu.:  0.0006           
 Max.   :502.60   Max.   :491.55   Max.   :312.51   Max.   : 93.7538           

Here’s participant 200:

[1] 21 11
       hr             meanrr           sdnn            sdann             sdnnix           pnn50        
 Min.   : 65.34   Min.   :608.8   Min.   : 47.01   Min.   :  2.141   Min.   : 40.13   Min.   :0.07312  
 1st Qu.: 79.25   1st Qu.:685.4   1st Qu.: 60.43   1st Qu.: 20.557   1st Qu.: 56.24   1st Qu.:0.16667  
 Median : 81.15   Median :750.9   Median : 80.69   Median : 32.198   Median : 63.72   Median :0.20183  
 Mean   : 83.08   Mean   :745.1   Mean   : 86.25   Mean   : 49.430   Mean   : 75.14   Mean   :0.20711  
 3rd Qu.: 89.23   3rd Qu.:760.6   3rd Qu.: 87.92   3rd Qu.: 45.186   3rd Qu.: 77.41   3rd Qu.:0.27193  
 Max.   :100.53   Max.   :939.8   Max.   :209.57   Max.   :185.514   Max.   :183.63   Max.   :0.33333  
      sdsd            rmssd             irrr            madrr            Episodes
 Min.   : 42.43   Min.   : 42.42   Min.   : 62.50   Min.   :-23.438573   0: 8    
 1st Qu.: 63.03   1st Qu.: 62.96   1st Qu.: 74.22   1st Qu.:  0.000000   1:13    
 Median : 78.50   Median : 78.31   Median : 93.75   Median :  0.000000           
 Mean   : 80.12   Mean   : 79.78   Mean   : 95.61   Mean   :  1.116191           
 3rd Qu.: 94.27   3rd Qu.: 93.65   3rd Qu.:125.01   3rd Qu.:  0.000954           
 Max.   :144.77   Max.   :143.62   Max.   :156.26   Max.   : 15.625834           

And participant 205:

[1] 15 11
       hr             meanrr           sdnn            sdann            sdnnix          pnn50        
 Min.   : 75.37   Min.   :427.6   Min.   : 53.46   Min.   : 8.355   Min.   :33.23   Min.   :0.09091  
 1st Qu.: 83.17   1st Qu.:663.9   1st Qu.: 76.75   1st Qu.:28.537   1st Qu.:64.08   1st Qu.:0.20000  
 Median : 85.67   Median :707.9   Median : 81.81   Median :37.346   Median :69.13   Median :0.24194  
 Mean   : 92.91   Mean   :677.3   Mean   : 86.12   Mean   :45.911   Mean   :69.45   Mean   :0.22682  
 3rd Qu.: 91.22   3rd Qu.:733.3   3rd Qu.: 95.51   3rd Qu.:49.529   3rd Qu.:78.48   3rd Qu.:0.26491  
 Max.   :142.86   Max.   :813.2   Max.   :118.79   Max.   :99.376   Max.   :96.78   Max.   :0.28671  
      sdsd            rmssd             irrr            madrr            Episodes
 Min.   : 57.15   Min.   : 54.58   Min.   : 39.06   Min.   :-31.250715   0:7     
 1st Qu.: 69.55   1st Qu.: 69.29   1st Qu.: 78.13   1st Qu.: -7.812500   1:8     
 Median : 84.69   Median : 84.01   Median : 93.75   Median :  0.000238           
 Mean   : 85.09   Mean   : 84.38   Mean   : 93.75   Mean   : -2.083309           
 3rd Qu.: 91.83   3rd Qu.: 91.28   3rd Qu.:115.24   3rd Qu.:  3.907025           
 Max.   :133.22   Max.   :131.84   Max.   :156.26   Max.   : 15.625000           

We can examine the distributions of the three top importance variables too:

Notice the difference in the ranges of these variables.

In any case, both participants 200 and 205 have extremely small data sets; changing any parameters such as the random seed could easily invalidate these results. Let’s examine the second best predictions, participant 207 (who we examined before).

Participant 207

Once again, our top three variables are present.

I’m noticing that the good models all lack heavy tails. Participant 207’s data is very similar to 200, however, it has a tiny bump way out at 400 for sdnn; by comparison, participant 200 had a range within 250 for these three variables. Does this mean that our preprocessing should apply a ceiling to these three variables?

How do these important variables change for each event?

How are the decision trees structured?

Random forest is a simple algorithm with a complex explanation; it’s considered one of the more black box algorithms, as it’s not common to get too much detail about mechanics out of it. Nevertheless, we can derive some information by randomly selecting a tree and checking it’s mechanics. This is not how the overall model works though (the real algorithm draws samples repeatedly and builds on the errors of small decision trees).

LS0tCnRpdGxlOiAiQWxsIHRoZSBNb2RlbHMhIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpOb3cgdGhhdCB3ZSBrbm93IGhvdyB0byBtb2RlbCB1cmdlcyB1c2luZyBoZWFydCByYXRlLCB3ZSBjYW4gY29tcHV0ZSBtb2RlbHMgZm9yIGVhY2ggcGFydGljaXBhbnQgYW5kIGZvciB0aGUgZ2xvYmFsIGRhdGFzZXQuCgpgYGB7ciwgaW5jbHVkZT1GQUxTRX0KI0xpYnJhcmllcyBhbmQgZnVuY3Rpb25zCgpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShubmV0KQpsaWJyYXJ5KFJXZWthKQpXUE0oInJlZnJlc2gtY2FjaGUiKQpXUE0oInBhY2thZ2UtaW5mbyIsICJyZXBvc2l0b3J5IiwgIm5haXZlQmF5ZXNUcmVlIikKV1BNKCJpbnN0YWxsLXBhY2thZ2UiLCAibmFpdmVCYXllc1RyZWUiKQpXT1coIndla2EvY2xhc3NpZmllcnMvdHJlZXMvTkJUcmVlIikKTkJUcmVlID0gbWFrZV9XZWthX2NsYXNzaWZpZXIoIndla2EvY2xhc3NpZmllcnMvdHJlZXMvTkJUcmVlIikKbGlicmFyeShhZGEpCmxpYnJhcnkoZTEwNzEpCmxpYnJhcnkocmFuZG9tRm9yZXN0KQpsaWJyYXJ5KGNhcmV0KQpsaWJyYXJ5KHBhbmRlcikKbGlicmFyeShST0NSKQpsaWJyYXJ5KGRhdGEudGFibGUpCgpzb3VyY2UoIkhSX0ZlYXR1cmVfRW5naW5lZXJpbmcuUiIpCnNldC5zZWVkKDUpCmBgYAoKYGBge3IsIGluY2x1ZGU9RkFMU0V9CiNsb2FkIHRoZSBkYXRhIGFuZCBjcmVhdGUgYSBsaXN0IG9mIHBhcnRpY2lwYW50cwoKI2dldCB0aGUgSUJJCnBhdGhfdG9fZmlsZSA9ICIvVXNlcnMvdHRhcGVyYS9Eb2N1bWVudHMvUVBTIExvY2FsL0Vtb3RlL1BhcnRpY2lwYW50cy90ZW1wQWxsX0hSLmNzdiIKZiA9IGZyZWFkKHBhdGhfdG9fZmlsZSwgaGVhZGVyPVQsIHNlcCA9ICIsIiklPiUKICBhcy5kYXRhLmZyYW1lKCkKCmlkcyA9IHVuaXF1ZShmJFBhcnRpY2lwYW50X0lEKQpwYXJ0aWNpcGFudF9pZHMgPSBwYXN0ZTAoInAiLCBpZHMpCnBhcnRzID0gbGlzdCgpCgpmb3IoeCBpbiAxOmxlbmd0aChwYXJ0aWNpcGFudF9pZHMpKXsKICBwYXJ0c1tbcGFydGljaXBhbnRfaWRzW3hdXV0gPSBmJT4lCiAgICBmaWx0ZXIoUGFydGljaXBhbnRfSUQgPT0gaWRzW3hdKSU+JQogICAgZ3JvdXBfYnkoU2Vzc2lvbl9TdGFydCklPiUKICAgIGFycmFuZ2UoU2Vzc2lvbl9TdGFydCkKICAKICB0MCA9IHBhcnRzW1twYXJ0aWNpcGFudF9pZHNbeF1dXSRCZWF0WzFdCiAgcGFydHNbW3BhcnRpY2lwYW50X2lkc1t4XV1dJEJlYXQyID0gcGFydHNbW3BhcnRpY2lwYW50X2lkc1t4XV1dJFNlc3Npb25fU3RhcnQgLSB0MCArIHBhcnRzW1twYXJ0aWNpcGFudF9pZHNbeF1dXSRCZWF0Cn0KCiNnZXQgbGFwc2VzCnBhdGhfdG9fZmlsZSA9ICIvVXNlcnMvdHRhcGVyYS9Eb2N1bWVudHMvUVBTIExvY2FsL0Vtb3RlL1BhcnRpY2lwYW50cy90ZW1wTGFwc2VzLmNzdiIKcGFydHMkTGFwc2VzID0gZnJlYWQocGF0aF90b19maWxlLCBoZWFkZXI9VCwgc2VwID0gIiwiKSU+JQogIGFzLmRhdGEuZnJhbWUoKQpwYXJ0cyRMYXBzZXMkRGF0ZSA9IHBhcnRzJExhcHNlcyRMYXBzZSU+JQogIGFzLlBPU0lYY3Qob3JpZ2luID0gIjE5NzAtMDEtMDEiLCB0eiA9ICJFU1QiKQpgYGAKCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQpMT05HID0gNTAgI251bWJlciBvZiBiZWF0cyB0byBjYWxjdWxhdGUgdGhlIHVwZGF0ZWQgbWVhbgpMQVNUID0gMTMgI2luaXRpYWwgdGhyZXNob2xkCk1JTl9CUE0gPSAyNSAjbWluaW11bSBwaHlzaW9sb2dpY2FsbHkgYWNjZXB0YWJsZSB2YWx1ZSBmb3IgSFIKTUFYX0JQTSA9IDIwMCAjbWF4aW11bSBwaHlzaW9sb2dpY2FsbHkgYWNjZXB0YWJsZSB2YWx1ZSBmb3IgSFIKCkZPTEQgPSAwLjI1ICNwb3J0aW9uIG9mIHRlc3QgZGF0YQpXSU5ET1dfU0laRSA9IDMwMCAjbnVtYmVyIG9mIHNlY29uZHMgaW4gdGhlIHNsaWRpbmcgd2luZG93CldJTkRPV19TVEVQID0gNSAjbnVtYmVyIG9mIHNlY29uZHMgdG8gbW92ZSB0aGUgc2xpZGluZyB3aW5kb3cgYnkKTE9PS0JBQ0sgPSA2MCozMCAjbnVtYmVyIG9mIHNlY29uZHMgaW4gYW4gb2JzZXJ2YXRpb24gKGllIG4gc2Vjb25kcyBiZWZvcmUgdGhlIHJlcG9ydGVkIGVwaXNvZGUpCgpjb2xzID0gYygiaHIiLCJtZWFucnIiLCJzZG5uIiwic2Rhbm4iLCJzZG5uaXgiLCAicG5uNTAiLCAic2RzZCIsICJybXNzZCIsICJpcnJyIiwgIm1hZHJyIikKcGFydGljaXBhbnRfaWRzMiA9IGMocGFydGljaXBhbnRfaWRzLCJHbG9iYWwiKQpgYGAKCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIEJ1aWxkIHRoZSBkYXRhc2V0ICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgpocnYgPSBsaXN0KCkKCmZvcihwIGluIDE6bGVuZ3RoKGlkcykpewogIAogIHJyID0gcHJlcHJvY2Vzc19IUihwYXJ0c1tbcGFydGljaXBhbnRfaWRzW3BdXV0kQmVhdDIsIHBhcnRzW1twYXJ0aWNpcGFudF9pZHNbcF1dXSRTZXNzaW9uX1N0YXJ0WzFdLCBMT05HLCBMQVNULCBNSU5fQlBNLCBNQVhfQlBNKQoKICBsYXBzZXMgPSBwYXJ0cyRMYXBzZXMlPiUKICAgIGZpbHRlcihQYXJ0aWNpcGFudF9JRCA9PSBpZHNbcF0pCiAgCiAgbGFwc2VfZGYgPSBkYXRhLmZyYW1lKG1hdHJpeChuY29sID0gbGVuZ3RoKGNvbHMpKSkKICBjb2xuYW1lcyhsYXBzZV9kZikgPSBjb2xzCiAgZm9yKHggaW4gMTpucm93KGxhcHNlcykpewogICAgZGF0ID0gZXh0cmFjdF9mZWF0dXJlcyhyciwgV0lORE9XX1NJWkUsIFdJTkRPV19TVEVQLCBsYXBzZXMkTGFwc2VbeF0sIExPT0tCQUNLKQogICAgbGFwc2VfZGYgPSByYmluZChsYXBzZV9kZiwgZGF0KQogIH0KICAKICBsYXBzZV9kZiA9IGxhcHNlX2RmW2NvbXBsZXRlLmNhc2VzKGxhcHNlX2RmKSxdCiAgbGFwc2VfZGYkWSA9IDEKICAKICBub25fbGFwc2VkZiA9IGxhcHNlX2RmW0ZBTFNFLF0KICBmb3IoeCBpbiAxOm5yb3cobGFwc2VzKSl7CiAgICBkYXQgPSBmaW5kX25vbmxhcHNlKHJyLCBXSU5ET1dfU0laRSwgV0lORE9XX1NURVAsIGxhcHNlcyRMYXBzZVt4XSwgTE9PS0JBQ0spCiAgICBub25fbGFwc2VkZiA9IHJiaW5kKG5vbl9sYXBzZWRmLCBkYXQpCiAgfQogIAogIG5vbl9sYXBzZWRmID0gbm9uX2xhcHNlZGZbY29tcGxldGUuY2FzZXMobm9uX2xhcHNlZGYpLF0KICBub25fbGFwc2VkZiRZID0gMAogIAogIGhydltbcF1dID0gcGFydGl0aW9uKGxhcHNlX2RmLG5vbl9sYXBzZWRmLEZPTEQpCgp9CgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIEFkZCBHbG9iYWwgZGF0YSAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKdHJhaW4gPSBOVUxMCnRlc3QgPSBOVUxMCgpmb3IoeCBpbiAxOmxlbmd0aChocnYpKXsKICB0cmFpbiA9IHJiaW5kKHRyYWluLCBocnZbW3hdXSR0cmFpbikKICB0ZXN0ID0gcmJpbmQodGVzdCwgaHJ2W1t4XV0kdGVzdCkKfQoKaHJ2W1tsZW5ndGgocGFydGljaXBhbnRfaWRzMildXSA9IGxpc3QodHJhaW49dHJhaW4sdGVzdD10ZXN0KQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIE1vZGVsbGluZyAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgpocnZfcHJlZCA9IGxhcHBseShocnYsIGZ1bmN0aW9uKHgpIGJ1aWxkX21vZGVscyh4KSkKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyBNb2RlbGxpbmcgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKZnVsbF9yZXN1bHRzID0gZGF0YS5mcmFtZSgpCmZvcih4IGluIDE6bGVuZ3RoKGhydl9wcmVkKSl7CiAgUGFydGljaXBhbnQgPSBwYXJ0aWNpcGFudF9pZHMyW3hdCiAgZm9yKHkgaW4gMTpsZW5ndGgoaHJ2X3ByZWRbW3hdXSkpewogICAgTW9kZWwgPSBuYW1lcyhocnZfcHJlZFtbeF1dKVt5XQogICAgaHJ2X3ByZWRbW3hdXVtbeV1dJHJlc3VsdHMgPSBocnZfcHJlZFtbeF1dW1t5XV0kcHJlZGljdGlvbnMlPiUKICAgICAgR2V0UmVzdWx0cygpCiAgICBmdWxsX3Jlc3VsdHMgPSBkYXRhLmZyYW1lKFBhcnRpY2lwYW50LCBNb2RlbCwgaHJ2X3ByZWRbW3hdXVtbeV1dJHJlc3VsdHMpJT4lCiAgICAgIHJiaW5kKGZ1bGxfcmVzdWx0cywuKQogIH0KfQpgYGAKCmBgYHtyLCBlY2hvPUZBTFNFfQpkZjEgPSBmdWxsX3Jlc3VsdHMKbW9kZWxzMSA9IGhydl9wcmVkCm5hbWVzKG1vZGVsczEpID0gcGFydGljaXBhbnRfaWRzMgpgYGAKCiMgSW50ZXJlc3RpbmcgUXVlcmllcwoKIyMgV2hhdCB3ZXJlIHRoZSBiZXN0IG92ZXJhbGwgcHJlZGljdGlvbnM/CgpIZXJlLCB3ZSBvcmRlciB0aGUgdmFsdWVzIHByaW9yaXRpc2luZyBgYWNjdXJhY3lgLCBmb2xsb3dlZCBieSBgc2Vuc2l0aXZpdHlgIChhYmlsaXR5IHRvIGNvcnJlY3RseSBkZXRlY3QgYW4gdXJnZS9lcGlzb2RlKSwgYW5kIGxhc3RseSBgc3BlY2lmaWNpdHlgIChhYmlsaXR5IHRvIGNvcnJlY3RseSByZWplY3Qgbm9uLXVyZ2VzKS4KCmBgYHtyLCBlY2hvPUZBTFNFfQpkZjElPiUKICBhcnJhbmdlKGRlc2MoQWNjdXJhY3kpLGRlc2MoU2Vuc2l0aXZpdHkpLGRlc2MoU3BlY2lmaWNpdHkpKSU+JQogIHRvcF9uKDEwLCBBY2N1cmFjeSkKYGBgCgpGcm9tIHRoaXMsIEkgd29uZGVyIGhvdyB3ZSBjYW4gZGVjaWRlIHRoZSBiZXN0IG1vZGVsLi4uCgojIyBXaGF0IHdlcmUgdGhlIGJlc3QgcHJlZGljdGlvbnMgZm9yIGVhY2ggcGFydGljaXBhbnQ/CgpgYGB7ciwgZWNobz1GQUxTRX0KZGYxJT4lCiAgZ3JvdXBfYnkoUGFydGljaXBhbnQpJT4lCiAgYXJyYW5nZShQYXJ0aWNpcGFudCxkZXNjKEFjY3VyYWN5KSxkZXNjKFNlbnNpdGl2aXR5KSxkZXNjKFNwZWNpZmljaXR5KSklPiUKICB0b3BfbigxLCBBY2N1cmFjeSkKYGBgCgpXZSBjYW4gc2VlIHRoYXQgcmFuZG9tIGZvcmVzdCBpcyBxdWl0ZSBwb3B1bGFyIChldmVuIHRob3VnaCBpdHMgZ2xvYmFsIHByZWRpY3Rpb24gd2FzIGxvdywgYXMgY29tcGFyZWQgdG8gdGhpcyBzdWJzZXQpOgoKYGBge3IsIGVjaG89RkFMU0V9CmRmMSU+JQogIGdyb3VwX2J5KFBhcnRpY2lwYW50KSU+JQogIGFycmFuZ2UoUGFydGljaXBhbnQsZGVzYyhBY2N1cmFjeSksZGVzYyhTZW5zaXRpdml0eSksZGVzYyhTcGVjaWZpY2l0eSkpJT4lCiAgdG9wX24oMSwgQWNjdXJhY3kpJT4lCiAgdW5ncm91cCgpJT4lCiAgY291bnQoTW9kZWwpJT4lCiAgYXJyYW5nZShkZXNjKG4pKQpgYGAKCmBgYHtyLCBlY2hvPUZBTFNFfQpkZjElPiUKICBnYXRoZXIoU3RhdCwgU2NvcmUsIDM6NSklPiUKICBnZ3Bsb3QoYWVzKHkgPSBTY29yZSwgeCA9IE1vZGVsKSkrCiAgZ2VvbV9ib3hwbG90KGFlcyhmaWxsID0gTW9kZWwpKSsKICAjZ2VvbV9qaXR0ZXIoYWVzKHdpZHRoID0gLTAuNiksIGFscGhhID0gMC40KSsKICBjb29yZF9mbGlwKCkrCiAgZmFjZXRfZ3JpZChTdGF0fi4pKwogIGdndGl0bGUoIkNvbXBhcmlzb24gb2YgTW9kZWwgUGVyZm9ybWFuY2Ugb24gXG5BY2N1cmFjeSwgU2Vuc2l0aXZpdHksICYgU3BlY2lmaWNpdHkiKQogIApgYGAKCkFjY29yZGluZyB0byB0aGlzIHBsb3QsIHRoZSByYW5kb20gZm9yZXN0IGNvbnNpc3RlbnRseSBwZXJmb3JtcyBiZXN0IChqdWRnaW5nIGJ5IHRoZSBtZWFuKS4gSXQgaXMgb25seSBvdXRwZXJmb3JtZWQgaW4gc2Vuc2l0aXZpdHksIGJ5IHRoZSBuZXVyYWwgbmV0ICh3aGljaCBoYXMgcG9vcmVzdCBtZWFuIGFjY3VyYWN5IGFuZCBtZWFuIHNwZWNpZmljaXR5KSBhbmQgdGhlIE5haXZlIEJheWVzaWFuIFRyZWUgKHdoaWNoIGFsc28gaGFzIHBvb3IgbWVhbiBzcGVjaWZpY2l0eSBieSBjb21wYXJpc29uKS4KCiMjIFNvIHdoYXQgZGlkIHJhbmRvbSBmb3Jlc3QgZG8/CgpgYGB7ciwgZWNobz1GQUxTRX0KZGYxJT4lCiAgZmlsdGVyKE1vZGVsID09ICJSRiIpJT4lCiAgYXJyYW5nZShkZXNjKEFjY3VyYWN5KSxkZXNjKFNlbnNpdGl2aXR5KSxkZXNjKFNwZWNpZmljaXR5KSkKYGBgCgpSYW5kb20gZm9yZXN0IHdhcyBhYmxlIHRvIGFjaGlldmUgMTAwJSBwcmVkaWN0aW9uIHJlc3VsdHMgb24gcGFydGljaXBhbnQgMjAwLCBhbmQgcGVyZm9ybWVkIHBvb3JseSB3aXRoIHBhcnRpY2lwYW50IDIwNS4KCiMjIFdoYXQgbWFrZXMgcGFydGljaXBhbnRzIDIwMCBhbmQgMjA1IG91dGxpZXJzIGluIHJhbmRvbSBmb3Jlc3QncyBvcGluaW9uPwoKRmlyc3QsIHdlIGNvbXBhcmUgdGhlIG1vZGVsIHNwZWNpZmljYXRpb25zOgoKYGBge3IsIGVjaG89RkFMU0V9Cm1vZGVsczEkcDIwMCRSRiRvYmplY3QlPiUKICB2YXJJbXBQbG90KG1haW4gPSAiUGFydGljaXBhbnQgMjAwIFZhcmlhYmxlIEltcG9ydGFuY2UgUGxvdCAoQmVzdCBNb2RlbCkiKQpgYGAKCmBgYHtyLCBlY2hvPUZBTFNFfQptb2RlbHMxJHAyMDUkUkYkb2JqZWN0JT4lCiAgdmFySW1wUGxvdChtYWluID0gIlBhcnRpY2lwYW50IDIwNSBWYXJpYWJsZSBJbXBvcnRhbmNlIFBsb3QgKFdvcnN0IE1vZGVsKSIpCmBgYAoKYGBge3IsIGVjaG89RkFMU0V9Cm1vZGVsczEkR2xvYmFsJFJGJG9iamVjdCU+JQogIHZhckltcFBsb3QobWFpbiA9ICJHbG9iYWwgTW9kZWwgVmFyaWFibGUgSW1wb3J0YW5jZSBQbG90IChBdmVyYWdlIE1vZGVsKSIpCmBgYAoKQnkgdGhlc2UgcGxvdHMsIHdlIGNhbiBhZ3JlZSB0aGF0IHRoZSB2YXJpYWJsZXMgYHNkbm5gLCBgc2Rhbm5gLCBhbmQgYHNkbm5peGAgYXJlIHByb2JhYmx5IG1vc3QgaW1wb3J0YW50IGFzIHRoZXkgYXJlIGZvdW5kIGhpZ2hlc3QgYm90aCBpbiB0aGUgZ2xvYmFsIGFuZCBiZXN0IG1vZGVsLiBMZXQncyBjb25maXJtIGJ5IHJhbmtpbmcgdGhlIHZhcmlhYmxlIGltcG9ydGFuY2UgaW4gZWFjaCBtb2RlbDoKCmBgYHtyLCBlY2hvPUZBTFNFfQpmZXRjaEltcCA9IGZ1bmN0aW9uKGxpc3RfZWwpewogIGltcG9ydGFuY2UobGlzdF9lbCRSRiRvYmplY3QpJT4lCiAgICBkYXRhLmZyYW1lKCklPiUKICAgIHJvd25hbWVzX3RvX2NvbHVtbigiVmFyaWFibGUiKSU+JQogICAgYXJyYW5nZShkZXNjKE1lYW5EZWNyZWFzZUdpbmkpKSU+JQogICAgc2VsZWN0KFZhcmlhYmxlKSU+JQogIHJldHVybigpCn0KCmw9bGFwcGx5KG1vZGVsczEsIGZ1bmN0aW9uKHgpIGZldGNoSW1wKHgpKSU+JQogIGJpbmRfY29scygpCm5hbWVzKGwpID0gcGFydGljaXBhbnRfaWRzMgoKZm9yKGMgaW4gMTpsZW5ndGgoY29scykpewogIHByaW50KHBhc3RlMCgiUmFua3MgZm9yIHZhcmlhYmxlIGAiLCBjb2xzW2NdLCAiYDoiKSkKICAKICB3aGljaChsID09IGNvbHNbY10sIGFyci5pbmQgPSBUKSU+JQogICAgZGF0YS5mcmFtZSgpJT4lCiAgICBjb3VudChyb3cpJT4lCiAgICBhcnJhbmdlKGRlc2MobikpJT4lCiAgICByZW5hbWUoUmFuayA9IHJvdywgbiA9IG4pJT4lCiAgICBwYW5kZXIoKQp9CmBgYAoKV2UgY2FuIGFzc3VtZSB0aGF0IHBhcnRpY2lwYW50IDIwNSBoYWQgdGhlIHBvb3Jlc3QgcHJlZGljdGlvbnMgYmVjYXVzZSB0aGVpciBtb2RlbCBzZWxlY3RlZCBwb29yIHZhcmlhYmxlcy4gV2hhdCBkbyB0aGVzZSB2YXJpYWJsZXMgbG9vayBsaWtlPwoKSGVyZSdzIHdoYXQgdGhlIGdsb2JhbCBkYXRhIHNldCBsb29rcyBsaWtlOgoKYGBge3IsIGVjaG89RkFMU0V9Cmhydltbd2hpY2gocGFydGljaXBhbnRfaWRzMiA9PSAiR2xvYmFsIildXSU+JQogIGJpbmRfcm93cygpJT4lCiAgZGltKCkKCmhydltbd2hpY2gocGFydGljaXBhbnRfaWRzMiA9PSAiR2xvYmFsIildXSU+JQogIGJpbmRfcm93cygpJT4lCiAgbXV0YXRlKEVwaXNvZGVzID0gYXMuZmFjdG9yKFkpLCBZPU5VTEwpJT4lCiAgc3VtbWFyeSgpCmBgYAoKSGVyZSdzIHBhcnRpY2lwYW50IDIwMDoKCmBgYHtyLCBlY2hvPUZBTFNFfQpocnZbW3doaWNoKHBhcnRpY2lwYW50X2lkczIgPT0gInAyMDAiKV1dJT4lCiAgYmluZF9yb3dzKCklPiUKICBkaW0oKQoKaHJ2W1t3aGljaChwYXJ0aWNpcGFudF9pZHMyID09ICJwMjAwIildXSU+JQogIGJpbmRfcm93cygpJT4lCiAgbXV0YXRlKEVwaXNvZGVzID0gYXMuZmFjdG9yKFkpLCBZPU5VTEwpJT4lCiAgc3VtbWFyeSgpCmBgYAoKQW5kIHBhcnRpY2lwYW50IDIwNToKCmBgYHtyLCBlY2hvPUZBTFNFfQpocnZbW3doaWNoKHBhcnRpY2lwYW50X2lkczIgPT0gInAyMDUiKV1dJT4lCiAgYmluZF9yb3dzKCklPiUKICBkaW0oKQoKaHJ2W1t3aGljaChwYXJ0aWNpcGFudF9pZHMyID09ICJwMjA1IildXSU+JQogIGJpbmRfcm93cygpJT4lCiAgbXV0YXRlKEVwaXNvZGVzID0gYXMuZmFjdG9yKFkpLCBZPU5VTEwpJT4lCiAgc3VtbWFyeSgpCmBgYAoKV2UgY2FuIGV4YW1pbmUgdGhlIGRpc3RyaWJ1dGlvbnMgb2YgdGhlIHRocmVlIHRvcCBpbXBvcnRhbmNlIHZhcmlhYmxlcyB0b286CgpgYGB7ciwgZWNobz1GQUxTRX0KaHJ2W1t3aGljaChwYXJ0aWNpcGFudF9pZHMyID09ICJHbG9iYWwiKV1dJT4lCiAgYmluZF9yb3dzKCklPiUKICBzZWxlY3Qoc2RubjpzZG5uaXgpJT4lCiAgZ2F0aGVyKFZhcmlhYmxlLCBWYWx1ZSklPiUKICBnZ3Bsb3QoYWVzKHg9VmFsdWUpKSsKICBnZW9tX2RlbnNpdHkoYWVzKGNvbG9yID0gVmFyaWFibGUpKSsKICB0aGVtZV9taW5pbWFsKCkrCiAgZ2d0aXRsZSgiRGlzdHJpYnV0aW9uIG9mIDMgTW9zdCBJbXBvcnRhbnQgVmFyaWFibGVzXG5pbiB0aGUgR2xvYmFsIE1vZGVsIChBdmVyYWdlIE1vZGVsKSIpCmBgYAoKYGBge3IsIGVjaG89RkFMU0V9Cmhydltbd2hpY2gocGFydGljaXBhbnRfaWRzMiA9PSAicDIwMCIpXV0lPiUKICBiaW5kX3Jvd3MoKSU+JQogIHNlbGVjdChzZG5uOnNkbm5peCklPiUKICBnYXRoZXIoVmFyaWFibGUsIFZhbHVlKSU+JQogIGdncGxvdChhZXMoeD1WYWx1ZSkpKwogIGdlb21fZGVuc2l0eShhZXMoY29sb3IgPSBWYXJpYWJsZSkpKwogIHRoZW1lX21pbmltYWwoKSsKICBnZ3RpdGxlKCJEaXN0cmlidXRpb24gb2YgMyBNb3N0IEltcG9ydGFudCBWYXJpYWJsZXNcbmluIFBhcnRpY2lwYW50IDIwMCdzIE1vZGVsIChCZXN0IE1vZGVsKSIpCmBgYAoKYGBge3IsIGVjaG89RkFMU0V9Cmhydltbd2hpY2gocGFydGljaXBhbnRfaWRzMiA9PSAicDIwNSIpXV0lPiUKICBiaW5kX3Jvd3MoKSU+JQogIHNlbGVjdChzZG5uOnNkbm5peCklPiUKICBnYXRoZXIoVmFyaWFibGUsIFZhbHVlKSU+JQogIGdncGxvdChhZXMoeD1WYWx1ZSkpKwogIGdlb21fZGVuc2l0eShhZXMoY29sb3IgPSBWYXJpYWJsZSkpKwogIHRoZW1lX21pbmltYWwoKSsKICBnZ3RpdGxlKCJEaXN0cmlidXRpb24gb2YgMyBNb3N0IEltcG9ydGFudCBWYXJpYWJsZXNcbmluIFBhcnRpY2lwYW50IDIwNSdzIE1vZGVsIChXb3JzdCBNb2RlbCkiKQpgYGAKCk5vdGljZSB0aGUgZGlmZmVyZW5jZSBpbiB0aGUgcmFuZ2VzIG9mIHRoZXNlIHZhcmlhYmxlcy4KCkluIGFueSBjYXNlLCBib3RoIHBhcnRpY2lwYW50cyAyMDAgYW5kIDIwNSBoYXZlIGV4dHJlbWVseSBzbWFsbCBkYXRhIHNldHM7IGNoYW5naW5nIGFueSBwYXJhbWV0ZXJzIHN1Y2ggYXMgdGhlIHJhbmRvbSBzZWVkIGNvdWxkIGVhc2lseSBpbnZhbGlkYXRlIHRoZXNlIHJlc3VsdHMuIExldCdzIGV4YW1pbmUgdGhlIHNlY29uZCBiZXN0IHByZWRpY3Rpb25zLCBwYXJ0aWNpcGFudCAyMDcgKHdobyB3ZSBleGFtaW5lZCBiZWZvcmUpLgoKIyMgUGFydGljaXBhbnQgMjA3CgpgYGB7ciwgZWNobz1GQUxTRX0KbW9kZWxzMSRwMjA3JFJGJG9iamVjdCU+JQogIHZhckltcFBsb3QobWFpbiA9ICJQYXJ0aWNpcGFudCAyMDcgVmFyaWFibGUgSW1wb3J0YW5jZVxuUGxvdCAoVmVyeSBHb29kIE1vZGVsKSIpCmBgYAoKT25jZSBhZ2Fpbiwgb3VyIHRvcCB0aHJlZSB2YXJpYWJsZXMgYXJlIHByZXNlbnQuCgpgYGB7ciwgZWNobz1GQUxTRX0KaHJ2W1t3aGljaChwYXJ0aWNpcGFudF9pZHMyID09ICJwMjA3IildXSU+JQogIGJpbmRfcm93cygpJT4lCiAgc2VsZWN0KHNkbm46c2Rubml4KSU+JQogIGdhdGhlcihWYXJpYWJsZSwgVmFsdWUpJT4lCiAgZ2dwbG90KGFlcyh4PVZhbHVlKSkrCiAgZ2VvbV9kZW5zaXR5KGFlcyhjb2xvciA9IFZhcmlhYmxlKSkrCiAgdGhlbWVfbWluaW1hbCgpKwogIGdndGl0bGUoIkRpc3RyaWJ1dGlvbnMgb2YgQWxsIFZhcmlhYmxlc1xuaW4gUGFydGljaXBhbnQgMjA3J3MgTW9kZWwgKFZlcnkgR29vZCBNb2RlbCkiKQpgYGAKCkknbSBub3RpY2luZyB0aGF0IHRoZSBnb29kIG1vZGVscyBhbGwgbGFjayBoZWF2eSB0YWlscy4gUGFydGljaXBhbnQgMjA3J3MgZGF0YSBpcyB2ZXJ5IHNpbWlsYXIgdG8gMjAwLCBob3dldmVyLCBpdCBoYXMgYSB0aW55IGJ1bXAgd2F5IG91dCBhdCA0MDAgZm9yIGBzZG5uYDsgYnkgY29tcGFyaXNvbiwgcGFydGljaXBhbnQgMjAwIGhhZCBhIHJhbmdlIHdpdGhpbiAyNTAgZm9yIHRoZXNlIHRocmVlIHZhcmlhYmxlcy4gRG9lcyB0aGlzIG1lYW4gdGhhdCBvdXIgcHJlcHJvY2Vzc2luZyBzaG91bGQgYXBwbHkgYSBjZWlsaW5nIHRvIHRoZXNlIHRocmVlIHZhcmlhYmxlcz8KCiMjIEhvdyBkbyB0aGVzZSBpbXBvcnRhbnQgdmFyaWFibGVzIGNoYW5nZSBmb3IgZWFjaCBldmVudD8KCmBgYHtyLCBlY2hvPUZBTFNFfQpmZXRjaERGcyA9IGZ1bmN0aW9uKGxpc3RfZWwpewogIGxpc3RfZWwlPiUKICAgIGJpbmRfcm93cygpJT4lCiAgICBkYXRhLmZyYW1lKCklPiUKICAgIHJldHVybigpCn0KCmwyID0gbGFwcGx5KGhydiwgZnVuY3Rpb24oeCkgZmV0Y2hERnMoeCkpW1tsZW5ndGgocGFydGljaXBhbnRfaWRzMildXQpsMiU+JQogIHNlbGVjdChvbmVfb2YoYygic2RubiIsICJzZGFubiIsICJzZG5uaXgiLCAiWSIpKSklPiUKICBncm91cF9ieShZKSU+JQogIG11dGF0ZShBdmdfc2RubiA9IG1lYW4oc2RubiksCiAgICAgICAgIEF2Z19zZGFubiA9IG1lYW4oc2Rhbm4pLAogICAgICAgICBBdmdfc2Rubml4ID0gbWVhbihzZG5uaXgpKSU+JQogIHNlbGVjdChZOkF2Z19zZG5uaXgpJT4lCiAgZGlzdGluY3QoKSU+JQogIGdhdGhlcihWYXJpYWJsZSwgVmFsdWUsIDI6NCklPiUKICBnZ3Bsb3QoYWVzKHg9VmFyaWFibGUsIHk9VmFsdWUpKSsKICBnZW9tX2JhcihhZXMoZmlsbD1hcy5mYWN0b3IoWSkpLCBzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb249ImRvZGdlIikrCiAgI2dlb21fdGV4dChhZXMobGFiZWwgPSByb3VuZChWYWx1ZSwzKSwgeCA9IFZhcmlhYmxlLCB5ID0gVmFsdWUpLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSwgdmp1c3QgPSAtMC42KSsKICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWU9Ik91dGNvbWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzPWMoMCwxKSwKICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscz1jKCJOb3JtYWwiLCAiRXBpc29kZS9VcmdlIikpKwogIGdndGl0bGUoIkNvbXBhcmluZyBPdXIgVmFyaWFibGVzIG9mIEludGVyZXN0IEJlZm9yZSBBbiBFcGlzb2RlL1VyZ2VcbmFuZCBEdXJpbmcgTm9ybWFsIEFjdGl2aXR5IikrCiAgdGhlbWVfbWluaW1hbCgpCmBgYAoKIyMgSG93IGFyZSB0aGUgZGVjaXNpb24gdHJlZXMgc3RydWN0dXJlZD8KClJhbmRvbSBmb3Jlc3QgaXMgYSBzaW1wbGUgYWxnb3JpdGhtIHdpdGggYSBjb21wbGV4IGV4cGxhbmF0aW9uOyBpdCdzIGNvbnNpZGVyZWQgb25lIG9mIHRoZSBtb3JlICpibGFjayBib3gqIGFsZ29yaXRobXMsIGFzIGl0J3Mgbm90IGNvbW1vbiB0byBnZXQgdG9vIG11Y2ggZGV0YWlsIGFib3V0IG1lY2hhbmljcyBvdXQgb2YgaXQuIE5ldmVydGhlbGVzcywgd2UgY2FuIGRlcml2ZSBzb21lIGluZm9ybWF0aW9uIGJ5IHJhbmRvbWx5IHNlbGVjdGluZyBhIHRyZWUgYW5kIGNoZWNraW5nIGl0J3MgbWVjaGFuaWNzLiBUaGlzIGlzIG5vdCBob3cgdGhlIG92ZXJhbGwgbW9kZWwgd29ya3MgdGhvdWdoICh0aGUgcmVhbCBhbGdvcml0aG0gZHJhd3Mgc2FtcGxlcyByZXBlYXRlZGx5IGFuZCBidWlsZHMgb24gdGhlIGVycm9ycyBvZiBzbWFsbCBkZWNpc2lvbiB0cmVlcykuCgpgYGB7ciwgd2FybmluZz1GQUxTRSwgZWNobz1GQUxTRX0KZm9yKHBwIGluIDE6bGVuZ3RoKG1vZGVsczEpKXsKICB0cmVlX2Z1bmMobW9kZWxzMVtbcHBdXSRSRiRvYmplY3QsIHNhbXBsZS5pbnQoMTptb2RlbHMxW1twcF1dJFJGJG9iamVjdCRudHJlZSwxKSwgcGFydGljaXBhbnRfaWRzMltwcF0pCn0KYGBgCgo=